﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using Fluid.Controls;
using Fluid.Drawing.GdiPlus;
using System.Drawing;
using System.Drawing.Imaging;
using System.ComponentModel;
using System.Collections.Specialized;
using TouchRC.Logic;

namespace TouchRC.Templates
{
    public class TransparentTemplate : FluidTemplate
    {
        #region Private Members

        private Bitmap cachedBitmap;
        private static HybridDictionary cachedBitmaps;
        private void InvalidateCache()
        {
            cachedBitmap = null;
            if (EnableCache && !Initializing)
            {
                CreateChachedBitmap();
            }
        }
        private int alpha = 255;
        private Size templateSize = Size.Empty;
        ImageAttributes ia = new ImageAttributes();
        private static Color transparentColor = Color.Fuchsia;
        private SolidBrush transparentBrush = new SolidBrush(transparentColor);
        private Image image;

        #endregion

        #region Accessors

        /// <summary>
        /// Gets or sets wether to enable a bitmap cache for the button for better performance.
        /// </summary>
        [DefaultValue(true)]
        public bool EnableCache { get; set; }

        public int Alpha
        {
            get { return alpha; }
            set
            {
                value = CheckAlphaBounds(value);
                if (value != alpha)
                {
                    alpha = value;
                    InvalidateCache();
                    Invalidate();
                }
            }
        }

        public Point TextOffset { get; set; }

        /// <summary>
        /// Gets or sets the size of the button.
        /// If set to Size.Empty, the size of the bounds is used.
        /// This property enables to scale the button and only works with double buffering.
        /// </summary>
        public Size TemplateSize
        {
            get { return templateSize; }
            set
            {
                if (templateSize != value)
                {
                    templateSize = value;
                    InvalidateCache();
                    Invalidate();
                }
            }
        }

        Rectangle TemplateRectangle
        {
            get
            {
                Size size = GetButtonSize();
                return new Rectangle(0, 0, size.Width, size.Height);
            }
        }

        protected StringFormat stringFormat = new StringFormat(System.Drawing.StringFormatFlags.NoWrap);
        
        /// <summary>
        /// Gets or sets an image for the button. Note that Color.Fuchsia is the transparent color.
        /// </summary>
        public Image Image
        {
            get { return image; }
            set
            {
                if (image != value)
                {
                    image = value;
                    OnImageChanged();
                }
            }
        }

        #endregion

        protected override void InitControl()
        {
            base.InitControl();
            EnableCache = true;
        }

        protected override void OnPaintBackground(FluidPaintEventArgs e)
        {
            //Size size = Bounds.Size;
            //if (size.Width <= 0 || size.Height <= 0) return;
            //if (EnableCache)
            //{
            //    PaintCached(e);
            //}
            //else
            //{
            //    PaintTemplateBackground(e);
            //}
        }

        protected virtual void PaintTemplateBackground(FluidPaintEventArgs e)
        {
            PerformPaintTemplateContent(e);
        }

        protected virtual void OnImageChanged()
        {
            InvalidateCache();
            Invalidate();
        }

        protected override void OnSizeChanged(Size oldSize, Size newSize)
        {
            base.OnSizeChanged(oldSize, newSize);
            InvalidateCache();
        }

        private int CheckAlphaBounds(int value)
        {
            if (value < 0) return 0;
            if (value > 255) return 255;
            return value;
        }

        private void PaintCached(FluidPaintEventArgs pe)
        {
            Bitmap bm = CreateChachedBitmap();
            Rectangle rect = pe.ControlBounds;
            ia.SetColorKey(transparentColor, transparentColor);
            if (alpha < 255)
            {
                GdiExt.AlphaBlendImage(pe.Graphics, bm, rect.X, rect.Y, alpha, true);
            }
            else
            {
                pe.Graphics.DrawImage(bm, rect, 0, 0, bm.Width, bm.Height, GraphicsUnit.Pixel, ia);
            }
        }

        /// <summary>
        /// Gets the key the identifies the button with its current properties and is unique.
        /// </summary>
        /// <returns>A string that represents the key.</returns>
        private string GetKey()
        {
            Size size = GetButtonSize();
            string imgKey = Image != null ? Image.GetHashCode().ToString() : string.Empty;
            return string.Format("{0},{1},{2},{3}_{4}_{5}{6}",
                size.Width, size.Height,
                BackColor.ToArgb(),
                IsDown ? 1 : 0,
                GetType().Name,
                Enabled ? "" : "0",
                imgKey);
        }

        private Bitmap CreateChachedBitmap()
        {
            Bitmap bm = cachedBitmap;
            if (bm == null)
            {
                if (cachedBitmaps == null) cachedBitmaps = new HybridDictionary();
                Rectangle r = ClientRectangle;
                string key = GetKey();
                if (cachedBitmaps.Contains(key))
                {
                    bm = cachedBitmaps[key] as Bitmap;
                }
                else
                {
                    bm = CreateBitmap(key);
                }
                cachedBitmap = bm;
            }
            return bm;
        }

        private Size GetButtonSize()
        {
            return templateSize.IsEmpty ? Bounds.Size : templateSize;
        }

        private Bitmap CreateBitmap(string key)
        {
            Size size = GetButtonSize();
            int w = Math.Max(size.Width, 2);
            int h = Math.Max(size.Height, 2);
            Bitmap bm = new Bitmap(w, h);
            using (Graphics g = Graphics.FromImage(bm))
            {
                transparentBrush.Color = transparentColor;
                g.FillRectangle(transparentBrush, 0, 0, bm.Width, bm.Height);
                //g.Clear(transparentColor);
                FluidPaintEventArgs pe = new FluidPaintEventArgs(g, ClientRectangle, ScaleFactor);
                PaintTemplateBackground(pe);
            }
            cachedBitmaps.Add(key, bm);
            return bm;
        }

        protected void PerformPaintTemplateContent(FluidPaintEventArgs e)
        {
            Rectangle rect = TemplateRectangle;
            //Color endColor = this.BackColor;
            Graphics g = e.Graphics;
            //rect.Offset(e.ControlBounds.X, e.ControlBounds.Y);
            //Color textColor = ForeColor;
            //if (!Enabled)
            //{
            //    textColor = ColorConverter.AlphaBlendColor(endColor, textColor, 32);
            //}
            //Brush foreBrush = Brushes.GetBrush(textColor);
            //StringFormat sf = this.stringFormat;
            //Rectangle r = rect;
            //r.Inflate(e.ScaleX(-3), e.ScaleY(2));
            //RectangleF rf = new RectangleF(r.Left, r.Top, r.Width, r.Height);
            
            //rf.X += (float)ScaleX(TextOffset.X);
            //rf.Y += (float)ScaleY(TextOffset.Y);

            //g.DrawString(string.Empty, Font, foreBrush, rf, sf);

            if (Image != null)
            {
                int imW = ScaleX(Image.Width);
                int imH = ScaleY(Image.Height);

                int w = Math.Min(imW, rect.Width);
                int h = Math.Min(imH, rect.Height);

                rect.Y += (rect.Height - h) / 2;
                rect.X += (rect.Width - h) / 2;
                rect.Width = w;
                rect.Height = h;
                ImageAttributes ia = new ImageAttributes();
                ia.SetColorKey(Color.Fuchsia, Color.Fuchsia);
                if (rect.Width > w)
                {
                    rect.X += (rect.Width - w) / 2;
                    rect.Width = w;
                }
                if (rect.Height > h)
                {
                    rect.X += (rect.Height - h) / 2;
                    rect.Height = h;
                }
                if (IsDown)
                {
                    rect.X++;
                    rect.Y++;
                }
                g.DrawImage(Image, rect, 0, 0, Image.Width, Image.Height, GraphicsUnit.Pixel, ia);
                //                g.DrawImage(Image, rect, new Rectangle(0, 0, imW, imH), GraphicsUnit.Pixel);
            }
        }

        
    }
}
